//
//  CDownLoadManager.m
//  Delicious
//
//  Created by yilong zhang on 11-11-21.
//  Copyright 2011年 __MyCompanyName__. All rights reserved.
//

#import "CDownLoadManager.h"
#import "COperation.h"

@class COperation;

//=========================================================================================================================

@implementation CTask

@synthesize m_Url;
@synthesize m_Data;
@synthesize m_UserInfo;
@synthesize m_PostData;
@synthesize m_nTimeOut;
@synthesize m_Sponsor;
@synthesize m_MType;
@synthesize m_Status;

@synthesize m_Operation;
    
-(id)initWithUrl:(NSString*)url Sponsor:(id)sponsor PostData:(NSData*)postdata TimeOut:(int)timeout Data:(id)data MType:(int)mtype UserInfo:(id)userinfo
{
    self = [super init];
    if (self)
    {
        self.m_Url        = url;
        self.m_Data       = data;
        self.m_UserInfo   = userinfo;
        self.m_PostData   = postdata;
        self.m_Sponsor    = sponsor;
        self.m_nTimeOut   = timeout;
        self.m_MType      = mtype;
        
        self.m_Status     = Wait;
        self.m_Operation  = nil;
    }
    
    return self;
}

-(void)dealloc
{
    //NSLog(@"CTask_dealloc");
    [m_Url release];
    [m_PostData release];
    [m_Data release];
    [m_UserInfo release];
    [m_Sponsor release];
    
    [super dealloc];
}

@end


//=========================================================================================================================

@implementation CDownLoadManager

static CDownLoadManager *g_Instance = nil;

@synthesize m_OperationQueue;
@synthesize m_StoreQueue;
@synthesize m_FreeQueue;
@synthesize m_TaskStack;
@synthesize m_TaskRunStack;
@synthesize m_Lock;
@synthesize m_MaxNum;

+(id)allocWithZone:(NSZone *)zone
{
    @synchronized(self)
    {
        if (nil == g_Instance)
        {
            g_Instance = [super allocWithZone:zone];
        }
    }
    
    return g_Instance;
}

+(CDownLoadManager*)DefaultDownLoadManager
{
    if (nil == g_Instance)
    {
        g_Instance = [[CDownLoadManager alloc] initWithOperationNum:8];
    }
    
    return g_Instance;
}

+(void)DestroyDownLoadManager
{
    [g_Instance release];
    g_Instance = nil;
}

- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
    }
    
    return self;
}

-(id)initWithOperationNum:(int)MaxOpNum
{
    self = [super init];
    if (self)
    {
        m_OperationQueue = [[NSOperationQueue alloc] init];
        [m_OperationQueue setMaxConcurrentOperationCount:-1];
        
        m_MaxNum       = MaxOpNum;
        m_StoreQueue   = [[NSMutableArray alloc] initWithCapacity:MaxOpNum];
        m_FreeQueue    = [[NSMutableArray alloc] initWithCapacity:MaxOpNum];
        m_TaskStack    = [[NSMutableArray array] retain];
        m_TaskRunStack = [[NSMutableArray array] retain];
        
        CNetWorkRequest *request = nil;
        for (int i=0; i<m_MaxNum; i++)
        {    
            request = [[CNetWorkRequest alloc] init];
            [m_StoreQueue addObject:request];
            [m_FreeQueue addObject:request];
            [request release];
        }
        
        m_Lock = [[NSCondition alloc] init];
    }
    
    return self;
}

-(void)dealloc
{
    [m_OperationQueue cancelAllOperations];
    [m_OperationQueue release];
    [m_TaskStack release];
    [m_TaskRunStack release];
    [m_FreeQueue release];
    [m_StoreQueue release];
    [m_Lock unlock];
    [m_Lock release];
    
    [super dealloc];
}

-(CTask*)AddTask:(NSString*)url Sponsor:(id)sponsor PostData:(NSData*)postdata TimeOut:(int)timeout Data:(id)data MType:(int)mtype UserInfo:(id)userinfo
{
    [m_Lock lock];
    
    //NSLog(@"<----AddTask(%@)---->", url);
    CTask *task = [[[CTask alloc] initWithUrl:url Sponsor:sponsor PostData:postdata TimeOut:timeout Data:data MType:mtype UserInfo:userinfo] autorelease];
    
    if ([m_FreeQueue count] > 0)
    {
        COperation *op = [[COperation alloc] initWithID:0 Delegate:self];
        
        CNetWorkRequest *request = [m_FreeQueue lastObject];
        task.m_Status = Run;
        [op SetOperation:task Request:request];
        [m_FreeQueue removeLastObject];
        [m_TaskRunStack addObject:task];
        
        [m_OperationQueue addOperation:op];
        [op release];
        
        //NSLog(@"<----立即开始任务(%d)---->", [m_FreeQueue count]);
    }
    //没有空闲操作可用进行排队
    else 
    {
        task.m_Status = Wait;
        [m_TaskStack addObject:task];
        
        //NSLog(@"<----任务排队中(%d_run(%d))---->", [m_FreeQueue count], [m_TaskRunStack count]);
    }
    
    [m_Lock unlock];
    
    //[task release];
    
    return task;
}

-(void)CancelTask:(CTask*)task
{
    [m_Lock lock];

    if (task)
    {
        if (Run == task.m_Status)
        {
            NSLog(@"CancelTask");
            [task.m_Operation cancelOperation];
            //COperation *op = task.m_NetWork.m_Delegate;
            //[op cancelOperation];
            //task.m_Sponsor = nil;
        }
        else if (Wait == task.m_Status)
        {
            [m_TaskStack removeObject:task];
        }
        else {;}
    }
    
    [m_Lock unlock];
}

-(void)CancelFinishedOperation:(COperation*)operation
{
    [m_Lock lock];
    
    [m_FreeQueue addObject:operation.m_UrlConnection];
    [m_TaskRunStack removeObject:operation.m_Task];
    
    //NSLog(@"<----任务完成，归还(%d__operationCount:%d__Count:%d)---->", [m_FreeQueue count], [m_OperationQueue operationCount], [[m_OperationQueue operations] count]);
    if (m_MaxNum == [m_FreeQueue count])
    {
        [m_OperationQueue cancelAllOperations];
        //NSLog(@"<----@@@---任务完成，归还(%d__operationCount:%d__Count:%d)---->", [m_FreeQueue count], [m_OperationQueue operationCount],[[m_OperationQueue operations] count]);
    }

    [m_Lock unlock];
}

-(void)DidTaskFinished:(COperation *)op
{
    [self CancelFinishedOperation:op];
    
    [self StartDownLoadTask];
}

-(void)StartDownLoadTask
{
    [m_Lock lock];
    
    if ([m_TaskStack count] > 0)
    {
        if ([m_FreeQueue count] > 0)
        {
            COperation *op = [[COperation alloc] initWithID:0 Delegate:self];
            CNetWorkRequest *request = [m_FreeQueue lastObject];
            CTask *task = [m_TaskStack lastObject];
            task.m_Status = Run;
            [m_TaskRunStack addObject:task];
            [m_TaskStack removeLastObject];
            [m_FreeQueue removeLastObject];
            [op SetOperation:task Request:request];
            [m_OperationQueue addOperation:op];
            [op release];
        }
    }
    else 
    {
        [m_OperationQueue cancelAllOperations];
    }
    
    [m_Lock unlock];
}

-(void)StopDwonLoadTask
{
    [m_Lock lock];
    
    [m_OperationQueue cancelAllOperations];
    
    [m_TaskStack removeAllObjects];
    [m_TaskRunStack removeAllObjects];
    [m_FreeQueue removeAllObjects];
    
    for (CNetWorkRequest *request in m_StoreQueue)
    {
        [request Stop];
        [m_FreeQueue addObject:request];
    }
    
    [m_Lock unlock];
}

@end
